﻿namespace TestTool.Tests.Common.Discovery
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Xml;
    using System.Xml.XPath;
    using TestTool.Proxies.Onvif;
    using TestTool.Proxies.WSDiscovery;
    using TestTool.Tests.Common.Soap;

    public class DiscoveryUtils
    {
        private static string[] _mandatoryScopes = new string[] { "onvif://www.onvif.org/hardware", "onvif://www.onvif.org/name" };
        public const string NVT_SCOPE = "onvif://www.onvif.org/type/Network_Video_Transmitter";
        private static DiscoveryType ONVIF_10_TYPE = new DiscoveryType("http://www.onvif.org/ver10/network/wsdl", "NetworkVideoTransmitter");
        public const string ONVIF_20_DEVICE_NS = "http://www.onvif.org/ver10/device/wsdl";
        public const string ONVIF_20_DEVICE_TYPE = "Device";
        private static DiscoveryType ONVIF_20_TYPE = new DiscoveryType("http://www.onvif.org/ver10/device/wsdl", "Device");
        public const string ONVIF_DISCOVER_TYPES = "NetworkVideoTransmitter";
        public const string ONVIF_NETWORK_WSDL_URL = "http://www.onvif.org/ver10/network/wsdl";
        public const string SOAP_ENVELOPE_NS = "http://www.w3.org/2003/05/soap-envelope";
        public const string WS_DISCOVER_ADDRESSING_NS = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
        public const string WS_DISCOVER_NS = "http://schemas.xmlsoap.org/ws/2005/04/discovery";

        public static bool CheckDeviceHelloType(SoapMessage<HelloType> message, out string reason)
        {
            return CheckDeviceType(message.Raw, "/s:Envelope/s:Body/wsd:Hello/wsd:Types", message.Object.Scopes, out reason);
        }

        public static bool CheckDeviceMatchType(SoapMessage<ProbeMatchesType> message, int matchNumber)
        {
            string str;
            return CheckDeviceMatchType(message, matchNumber, out str);
        }

        public static bool CheckDeviceMatchType(SoapMessage<ProbeMatchesType> message, int matchNumber, out string reason)
        {
            return CheckDeviceType(message.Raw, string.Format("/s:Envelope/s:Body/wsd:ProbeMatches/wsd:ProbeMatch/wsd:Types[{0}]", matchNumber + 1), message.Object.ProbeMatch[matchNumber].Scopes, out reason);
        }

        public static bool CheckDeviceMatchType(SoapMessage<ProbeMatchesType> message, int matchNumber, DiscoveryType[][] requestTypes)
        {
            string typesPath = string.Format("/s:Envelope/s:Body/wsd:ProbeMatches/wsd:ProbeMatch/wsd:Types[{0}]", matchNumber + 1);
            bool flag = false;
            foreach (DiscoveryType[] typeArray in requestTypes)
            {
                if (flag = flag || CheckDeviceType(message.Raw, typesPath, typeArray))
                {
                    return flag;
                }
            }
            return flag;
        }

        private static bool CheckDeviceType(byte[] message, string typesPath, DiscoveryType[] requestTypes)
        {
            bool flag = true;
            MemoryStream stream = new MemoryStream(message);
            try
            {
                XPathNavigator navigator = new XPathDocument(stream).CreateNavigator();
                XmlNamespaceManager resolver = new XmlNamespaceManager(navigator.NameTable);
                resolver.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
                resolver.AddNamespace("wsd", "http://schemas.xmlsoap.org/ws/2005/04/discovery");
                XPathNavigator navigator2 = navigator.SelectSingleNode(typesPath, resolver);
                if ((navigator2 == null) || string.IsNullOrEmpty(navigator2.InnerXml))
                {
                    return flag;
                }
                IDictionary<string, string> namespacesInScope = navigator2.GetNamespacesInScope(XmlNamespaceScope.All);
                string[] strArray = navigator2.InnerXml.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (DiscoveryType type in requestTypes)
                {
                    string str = type.Type;
                    string uriA = type.Namespace;
                    bool flag2 = false;
                    foreach (string str3 in strArray)
                    {
                        string[] strArray2 = str3.Split(new char[] { ':' });
                        if ((strArray2.Length == 2) && (strArray2[1] == str))
                        {
                            string key = strArray2[0];
                            if (namespacesInScope.ContainsKey(key) && CompareUri(uriA, namespacesInScope[key]))
                            {
                                flag2 = true;
                                break;
                            }
                        }
                    }
                    flag = flag && flag2;
                }
            }
            finally
            {
                stream.Close();
            }
            return flag;
        }

        private static bool CheckDeviceType(byte[] message, string typesPath, ScopesType scopes, out string reason)
        {
            bool flag = CheckDeviceType(message, typesPath, GetOnvif10Type());
            if (flag)
            {
                reason = string.Empty;
                return flag;
            }
            reason = string.Format("Device type is not {0} with namespace {1}", "NetworkVideoTransmitter", "http://www.onvif.org/ver10/network/wsdl");
            return flag;
        }

        public static bool CompareAddresses(System.Net.IPAddress a, System.Net.IPAddress b)
        {
            bool flag = true;
            if ((a == null) && (b == null))
            {
                return true;
            }
            if ((a == null) || (b == null))
            {
                return false;
            }
            if (a.AddressFamily != b.AddressFamily)
            {
                return false;
            }
            if (a.AddressFamily == AddressFamily.InterNetworkV6)
            {
                byte[] addressBytes = a.GetAddressBytes();
                byte[] buffer2 = b.GetAddressBytes();
                for (int i = 0; i < addressBytes.Length; i++)
                {
                    if (addressBytes[i] != buffer2[i])
                    {
                        return false;
                    }
                }
                return flag;
            }
            return object.Equals(a, b);
        }

        public static bool CompareUri(string uriA, string uriB)
        {
            Uri objA = new Uri(uriA);
            Uri objB = new Uri(uriB);
            return object.Equals(objA, objB);
        }

        public static bool CompareUUID(string a, string b)
        {
            Guid guid = ParseUUID(a);
            Guid guid2 = ParseUUID(b);
            return (guid == guid2);
        }

        protected static string ExtractElementValue(byte[] xml, string element, string elementNSUri)
        {
            string innerXml = string.Empty;
            MemoryStream stream = new MemoryStream(xml);
            XPathDocument document = new XPathDocument(stream);
            XPathNodeIterator iterator = document.CreateNavigator().SelectDescendants(element, elementNSUri, false);
            if (iterator.Count == 1)
            {
                iterator.MoveNext();
                innerXml = iterator.Current.InnerXml;
            }
            stream.Close();
            return innerXml;
        }

        public static string ExtractMessageId(byte[] message)
        {
            return ExtractElementValue(message, "MessageID", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
        }

        public static string ExtractRelatesTo(ICollection<XmlElement> header)
        {
            string str = string.Empty;
            foreach (XmlElement element in header)
            {
                if ((element.LocalName == "RelatesTo") && CompareUri(element.NamespaceURI, "http://schemas.xmlsoap.org/ws/2004/08/addressing"))
                {
                    return element.InnerText;
                }
            }
            return str;
        }

        protected static bool FindScope(IEnumerable<string> scopes, string scope)
        {
            foreach (string str in scopes)
            {
                if (str.StartsWith(scope, true, CultureInfo.InvariantCulture))
                {
                    return true;
                }
            }
            return false;
        }

        protected static bool FindScopeExact(IEnumerable<string> scopes, string scope)
        {
            foreach (string str in scopes)
            {
                if (StringComparer.InvariantCulture.Compare(str, scope) == 0)
                {
                    return true;
                }
            }
            return false;
        }

        public static string GetDeviceId(ByeType bye)
        {
            string str = string.Empty;
            if (((bye != null) && (bye.EndpointReference != null)) && (bye.EndpointReference.Address != null))
            {
                str = bye.EndpointReference.Address.Value;
            }
            return str;
        }

        public static string GetDeviceId(HelloType hello)
        {
            string str = string.Empty;
            if (((hello != null) && (hello.EndpointReference != null)) && (hello.EndpointReference.Address != null))
            {
                str = hello.EndpointReference.Address.Value;
            }
            return str;
        }

        public static string GetDeviceId(ProbeMatchesType matches)
        {
            string str = string.Empty;
            if ((((matches != null) && (matches.ProbeMatch != null)) && ((matches.ProbeMatch.Length > 0) && (matches.ProbeMatch[0].EndpointReference != null))) && (matches.ProbeMatch[0].EndpointReference.Address != null))
            {
                str = matches.ProbeMatch[0].EndpointReference.Address.Value;
            }
            return str;
        }

        public static List<DeviceDiscoveryData> GetDevices(SoapMessage<ProbeMatchesType> message, System.Net.IPAddress sender, DiscoveryType[][] types)
        {
            List<DeviceDiscoveryData> list = new List<DeviceDiscoveryData>();
            if (message.Object.ProbeMatch != null)
            {
                for (int i = 0; i < message.Object.ProbeMatch.Length; i++)
                {
                    ProbeMatchType type = message.Object.ProbeMatch[i];
                    if ((type.XAddrs != null) && ((types == null) ? CheckDeviceMatchType(message, i) : CheckDeviceMatchType(message, i, types)))
                    {
                        DeviceDiscoveryData item = new DeviceDiscoveryData {
                            Type = type.Types,
                            Scopes = type.Scopes.Text[0],
                            EndPointAddress = sender.ToString()
                        };
                        string[] collection = type.XAddrs.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        item.ServiceAddresses.AddRange(collection);
                        item.UUID = type.EndpointReference.Address.Value;
                        item.MetadataVersion = type.MetadataVersion;
                        list.Add(item);
                    }
                }
            }
            return list;
        }

        public static System.Net.IPAddress GetIP(string hostName, bool ipv6)
        {
            System.Net.IPAddress address = null;
            if (!string.IsNullOrEmpty(hostName))
            {
                try
                {
                    if (System.Net.IPAddress.TryParse(hostName, out address))
                    {
                        return address;
                    }
                    IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
                    if (hostEntry == null)
                    {
                        return address;
                    }
                    foreach (System.Net.IPAddress address2 in hostEntry.AddressList)
                    {
                        if (ipv6 && (address2.AddressFamily == AddressFamily.InterNetworkV6))
                        {
                            return address2;
                        }
                        if (!ipv6 && (address2.AddressFamily == AddressFamily.InterNetwork))
                        {
                            return address2;
                        }
                    }
                }
                catch
                {
                }
            }
            return address;
        }

        public static string[] GetManadatoryScopes()
        {
            return _mandatoryScopes;
        }

        public static string GetMissingMandatoryScope(string[] scopes)
        {
            return GetMissingScope(scopes, _mandatoryScopes);
        }

        public static string GetMissingMandatoryScope(TestTool.Proxies.Onvif.Scope[] scopes)
        {
            string[] strArray = new string[scopes.Length];
            int num = 0;
            foreach (TestTool.Proxies.Onvif.Scope scope in scopes)
            {
                strArray[num++] = scope.ScopeItem;
            }
            return GetMissingMandatoryScope(strArray);
        }

        public static string GetMissingScope(string[] deviceScopes, string[] scopesToCheck)
        {
            List<string> scopes = new List<string>();
            if (deviceScopes != null)
            {
                foreach (string str in deviceScopes)
                {
                    string[] separator = new string[] { Environment.NewLine, " " };
                    scopes.AddRange(str.Split(separator, StringSplitOptions.RemoveEmptyEntries));
                }
                foreach (string str2 in scopesToCheck)
                {
                    if (!FindScope(scopes, str2))
                    {
                        return str2;
                    }
                }
            }
            return string.Empty;
        }

        public static DiscoveryType[] GetOnvif10Type()
        {
            return new DiscoveryType[] { new DiscoveryType("http://www.onvif.org/ver10/network/wsdl", "NetworkVideoTransmitter", "dn") };
        }

        public static DiscoveryType[] GetOnvif20Type()
        {
            return new DiscoveryType[] { new DiscoveryType("http://www.onvif.org/ver10/device/wsdl", "Device", "tds") };
        }

        public static bool HasScope(IEnumerable<string> scopes, string scope)
        {
            return FindScopeExact(scopes, scope);
        }

        public static bool IsCorrectSoapFault(Fault fault, string code, string codeNS, string subcode, string subCodeNS, out string reason)
        {
            reason = null;
            if (fault.Code.Value.Name != code)
            {
                reason = string.Format("Invalid fault code returned. Expected: {0} - Actual: {1}", code, fault.Code.Value.Name);
                return false;
            }
            if (!CompareUri(fault.Code.Value.Namespace, codeNS))
            {
                reason = string.Format("Invalid fault code namespace. Expected: {0} - Actual: {1}", codeNS, fault.Code.Value.Namespace);
                return false;
            }
            if (fault.Code.Subcode.Value.Name != subcode)
            {
                reason = string.Format("Invalid fault subcode returned. Expected: {0} - Actual: {1}", subcode, fault.Code.Subcode.Value.Name);
                return false;
            }
            if (!CompareUri(fault.Code.Subcode.Value.Namespace, subCodeNS))
            {
                reason = string.Format("Invalid fault subcode namespace. Expected: {0} - Actual: {1}", subCodeNS, fault.Code.Subcode.Value.Namespace);
                return false;
            }
            return true;
        }

        protected static Guid ParseUUID(string uuid)
        {
            Guid empty = Guid.Empty;
            if (uuid.StartsWith("uuid:") && (uuid.Length > 5))
            {
                empty = new Guid(uuid.Substring(5, uuid.Length - 5));
            }
            return empty;
        }

        protected static XPathNavigator SelectChild(XPathNavigator navigator, string name, string namespaceURI)
        {
            XPathNavigator current = null;
            XPathNodeIterator iterator = navigator.SelectDescendants(name, namespaceURI, false);
            if (iterator.Count > 0)
            {
                iterator.MoveNext();
                current = iterator.Current;
            }
            return current;
        }

        protected static bool ValidateXMLValue(XPathNavigator navigator, string value, string expectedValue, string namespaceURI)
        {
            bool flag = false;
            string[] strArray = value.Split(new char[] { ':' });
            if (strArray.Length == 2)
            {
                string key = strArray[0];
                string str2 = strArray[1];
                if (str2 == value)
                {
                    IDictionary<string, string> namespacesInScope = navigator.GetNamespacesInScope(XmlNamespaceScope.All);
                    if (namespacesInScope.ContainsKey(key))
                    {
                        flag = CompareUri(namespacesInScope[key], namespaceURI);
                    }
                }
            }
            return flag;
        }

        public static string XmlToString(byte[] xml)
        {
            return Encoding.UTF8.GetString(xml);
        }

        public class DiscoveryType
        {
            public DiscoveryType(string ns, string type) : this(ns, type, string.Empty)
            {
            }

            public DiscoveryType(string ns, string type, string prefix)
            {
                this.Namespace = ns;
                this.Type = type;
                this.Prefix = prefix;
            }

            public string Namespace { get; set; }

            public string Prefix { get; set; }

            public string Type { get; set; }
        }
    }
}

